package com.foreveross.crawl.adapter.sub.impl20140402.v3.airfrance;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.foreveross.crawl.adapter.PlaneInfoEntityBuilder;
import com.foreveross.crawl.adapter.sub.impl20140402.v3.AirfranceAdapter;
import com.foreveross.crawl.common.util.RegHtmlUtil;
import com.foreveross.crawl.domain.airfreight.CabinEntity;
import com.foreveross.crawl.domain.airfreight.TransitEntity;
import com.foreveross.crawl.domain.airfreight.doub.CabinRelationEntity;
import com.foreveross.crawl.domain.airfreight.doub.DoublePlaneInfoEntity;
import com.foreveross.crawl.domain.airfreight.doub.ReturnCabinEntity;
import com.foreveross.crawl.domain.airfreight.doub.ReturnDoublePlaneInfoEntity;
import com.foreveross.crawl.domain.airfreight.doub.ReturnTransitEntity;
import com.foreveross.crawl.exception.FlightInfoNotFoundException;
import com.foreveross.crawl.util.DateUtil;
import com.foreveross.taskservice.common.bean.TaskModel;
import com.gargoylesoftware.htmlunit.NicelyResynchronizingAjaxController;
import com.gargoylesoftware.htmlunit.ScriptResult;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlInput;
import com.gargoylesoftware.htmlunit.html.HtmlPage;

/**
 * 法国航空往返，现只抓取直飞数据。后续如果要抓取全部，请在代码大致161行处去掉限制
 * 
 * @author fb
 */
@SuppressWarnings("deprecation")
public class AirfranceRoundV4 {

	private final static Logger logger = LoggerFactory.getLogger(AirfranceRound.class);

	private final String enterUrl = "http://www.airfrance.com.cn/cgi-bin/AF/CN/zh/local/process/standardbooking/ValidateSearchAction.do";
	
	// 出错后重复次数
	private final static int REPEATE_TIME = 3;
	
	private final static int PAGE_MAX_WAIT = 600;
	
	private final static boolean isFetchTaxation = true;

	private AirfranceAdapter adapter;

	private TaskModel taskQueue;
	
	private WebClient webClient;		
	
	private HtmlPage htmlPage;
	
	private List<DoublePlaneInfoEntity> planeInfos = new ArrayList<DoublePlaneInfoEntity>();
	
	public static enum CabinType {
		Y_MCHER("经济舱（最低票价）");
//		F_MCHER("头等舱"), 
//		C_MCHER("商务舱"), 
//		W_MCHER("尊尚经济舱 "), 
//		Y_FLEX("经济舱 (可免费更改)");
		
		private String lable;
		
		CabinType(String lable) {
			this.lable = lable;
		}
		
		public String getLable() {
			return this.lable;
		}
	}

	public AirfranceRoundV4(AirfranceAdapter adapter) {
		this.adapter = adapter;
		this.taskQueue = adapter.getTaskQueue();
	}

	public Object fetch() throws Exception {
		// 模仿浏览器从入口处进入
		webClient = adapter.getWebClientByFF();
		logActionInfo("模拟浏览器正在进入首页!");
		webClient.getPage(adapter.getUrl());
		hasWebClientRedirectEnabled();

		for (CabinType cabin : CabinType.values()) {
			fetchData(cabin);
		}
		
		if (planeInfos.isEmpty()) {
			throw new FlightInfoNotFoundException("没有此航班的信息!");
		}
		
		PlaneInfoEntityBuilder.buildLimitPrice(planeInfos);
		
		return planeInfos;
	}

	public List<DoublePlaneInfoEntity> flightInfoCrawl(String content) {

		return null;
	}

	private void fetchData(CabinType cabin) throws Exception {
		String flightListHtml = null;
		ScriptResult sr = null;
		logActionInfo(String.format("正在进入[%s]的第二日历选择页面!", cabin.getLable()));
		String page = errorRepeatExecute(getEnterParamsUrl(cabin.name()));
		
		// 获取到日历选择页面后进行页面校验
		if(true){//if (standardCalendarPageVerify(page))  {
			logActionInfo(String.format("程序正在[%s]日历选择页面模拟页面点击事件准备进入航班列表页!", cabin.getLable()));
			// 模拟点击下一部
//			sr = htmlPage.executeJavaScript("javascript:validate();");
//			// 暂时等待，不然获取不到数据
//			webClient.waitForBackgroundJavaScriptStartingBefore(PAGE_MAX_WAIT);
//			htmlPage = (HtmlPage) sr.getNewPage();
			flightListHtml =page;// htmlPage.asXml();
			
			// 列表数据验证
//			if (!flightListPageVerify(flightListHtml)) {
//				logActionInfo(String.format("程序[%s]获取航班列表页面内容不正确!", cabin.getLable()));
//				return;
//			}
		
		// 如果校验不通过，再看判断看程序是否自动跳到了第三列表页
		} /*else {
			flightListHtml = page;
			
			if (!flightListPageVerify(flightListHtml)) {
				return;
			}
			
			logActionInfo(String.format("程序自动己从[%s]日历选择页面跳到航班列表页面!", cabin.getLable()));
		}*/
		
		logActionInfo(String.format("程序准备解析[%s]获取的航班信息进行数据封装!", cabin.getLable()));
		// 列表解析与数据封装
		flightInfoAssembly(flightListHtml, cabin);
	}
	
	public void flightInfoAssembly(String flightListPage, CabinType cabin) throws Exception {
		Document doc = Jsoup.parse(flightListPage);
//		HtmlForm form = htmlPage.getFormByName("standardUpsellForm");
//		List<List<Map<String, String>>> outboundsData = new ArrayList<List<Map<String, String>>>();
//		List<List<Map<String, String>>> inboundsData = new ArrayList<List<Map<String, String>>>();
		List<Object> outboundsData=new ArrayList<Object>();
		List<Object> inboundsData=new ArrayList<Object>();
		
		Document detailDoc = null;
		
		ReturnDoublePlaneInfoEntity rdpe = null;
		Set<CabinEntity> cabins = null;
		Set<ReturnCabinEntity> returnCabins = null;
		
		// 数据解析封装
		flightInfoAnalysis(outboundsData, inboundsData, doc, cabin);
		
		logger.info("[{}]解析完成，正在准备数据组装!", cabin.getLable());
		// 数据组装
		for (Object outbound : outboundsData) {//去程
			DoublePlaneInfoEntity dpie = null;
			List<CabinInfo> outCabinfo=new ArrayList<CabinInfo>();//去程舱位组
			List<FlightInfo> outFlight=new ArrayList<FlightInfo>();//去程航班信息
			dpie=setDoubleInfo(outbound, taskQueue, cabin.getLable(),outCabinfo,outFlight);
			
			for (Object  inbound : inboundsData) {//回程
				List<CabinInfo> inCabinfo=new ArrayList<CabinInfo>();//回程舱位组
				List<FlightInfo> inFlight=new ArrayList<FlightInfo>();//回程航班信息
				rdpe =setRetrunInfo(inbound, taskQueue, cabin.getLable(), inCabinfo,inFlight);
				dpie.getReturnPlaneInfos().add(rdpe);
				
				//处理对应舱位，对应的税收，价格
				String detail = "";
				try {
					for(CabinInfo outInfo:outCabinfo){
						for(CabinInfo inInfo:inCabinfo){
							detail =errorRepeatExecute(getPriceParams(outInfo,inInfo,outFlight,inFlight));
							if (StringUtils.isBlank(detail)) {
								logger.error("正在获取仓位为[{}],去程id为[{}],回程id为[{}]的详细信息失败!", new Object[]{cabin.getLable(), outbound, inbound});
								continue;
							}
							detailDoc = Jsoup.parse(detail);
							// 仓位关系组装
							analyzeCabinRelation(detailDoc, dpie, cabins, returnCabins);
							
						}
					}
					
				} catch (Exception e) {
					e.printStackTrace();
				}
				
				planeInfos.add(dpie);
			}
			
			
		}
	}
	
	
	//组装去程基本信息
	public DoublePlaneInfoEntity setDoubleInfo(Object bounds, TaskModel taskQueue, String cabinTypeLabe ,List<CabinInfo> cabinfos,List<FlightInfo> outFlight) throws Exception{
		DoublePlaneInfoEntity dpie = null;
		Set<Object> objS=new LinkedHashSet<Object>();
		objS=(Set<Object>) bounds;
		int i=1;
		if(objS.size()==2){
			for (Object obj : objS) {
				if (i == 1) {
					// 航班基础信息
					List<FlightInfo> infoLists=(List<FlightInfo>)obj;
					outFlight.addAll(infoLists);
					for(int j=0;j<infoLists.size();j++){
						FlightInfo info=infoLists.get(j);
						if(j==0){//第一次航程信息
							dpie = PlaneInfoEntityBuilder.buildPlaneInfo(taskQueue, info.getFlightNo().substring(0,2), "法航", "法国航空公司", info.getStartTime(),null, info.getFlightNo(), null, info.getAgentName() ,null, info.getFlightType(), DoublePlaneInfoEntity.class);
							dpie.setCurrency("CNY");
							dpie.setFlightDuration(info.getFlightDuration());
						}
						if(infoLists.size()>1){//中转
							TransitEntity tr=new TransitEntity();
							tr.setFlightNo(info.getFlightNo());
							tr.setStartTime(setFlightDate(taskQueue,info.getStartTime(),false));
							tr.setEndTime(setFlightDate(taskQueue,info.getEndTime(),false));
							tr.setFlightType(info.getFlightType());
							tr.setCarrierKey(info.getFlightNo().substring(0,2));
							tr.setFromAirPortName(info.getFromAirportName());
							tr.setToAirPortName(info.getToAirportName());
							tr.setCarrierFullName(info.getAgentName());
							tr.setStayTime(info.getStopTime());
							dpie.getTransits().add(tr);
						}
						if(j==infoLists.size()-1){
							dpie.setEndTime(setFlightDate(taskQueue,info.getEndTime(),false));
						}
					}
					
				}
				if (i == 2) {
					// 舱位信息
					List<CabinInfo> cabinLists=(List<CabinInfo>)obj;
					cabinfos.addAll(cabinLists);
					for(int k=0;k<cabinLists.size();k++){
						CabinEntity e=new CabinEntity();
						CabinInfo cabinfo=cabinLists.get(k);
						e.setPrice(cabinfo.getPrice());
						e.setCabinType(cabinTypeLabe);
						e.setProductName(cabinfo.getCabinClass());
						e.setSubCabinName(cabinfo.getRecommendation());
						dpie.getCabins().add(e);
					}
				}
				i++;
			}
		}
		return dpie;
	}
	
	
	
	
	//组装回程基本信息
	public ReturnDoublePlaneInfoEntity setRetrunInfo(Object bounds, TaskModel taskQueue, String cabinTypeLabe ,List<CabinInfo> cabinfos,List<FlightInfo> inFlight) throws Exception{
		ReturnDoublePlaneInfoEntity dpie = null;
		Set<Object> objS=new LinkedHashSet<Object>();
		objS=(Set<Object>) bounds;
		int i=1;
		if(objS.size()==2){
			for (Object obj : objS) {
				if (i == 1) {
					// 航班基础信息
					List<FlightInfo> infoLists=(List<FlightInfo>)obj;
					inFlight.addAll(infoLists);
					for(int j=0;j<infoLists.size();j++){
						FlightInfo info=infoLists.get(j);
						if(j==0){//第一次航程信息
							dpie =  PlaneInfoEntityBuilder.buildPlaneInfo(taskQueue, info.getFlightNo().substring(0,2), "法航", "法国航空公司", info.getStartTime(),null, info.getFlightNo(), null, info.getAgentName() ,null, info.getFlightType(), ReturnDoublePlaneInfoEntity.class);;
							dpie.setCurrency("CNY");
							dpie.setFlightDuration(info.getFlightDuration());
						}
						if(infoLists.size()>1){//中转
							ReturnTransitEntity tr=new ReturnTransitEntity();
							tr.setFlightNo(info.getFlightNo());
							tr.setStartTime(setFlightDate(taskQueue,info.getStartTime(),true));
							tr.setEndTime(setFlightDate(taskQueue,info.getEndTime(),true));
							tr.setFlightType(info.getFlightType());
							tr.setCarrierKey(info.getFlightNo().substring(0,2));
							tr.setFromAirPortName(info.getFromAirportName());
							tr.setToAirPortName(info.getToAirportName());
							tr.setCarrierFullName(info.getAgentName());
							tr.setStayTime(info.getStopTime());
							dpie.getReturnTransits().add(tr);
						}
						if(j==infoLists.size()-1){
							dpie.setEndTime(setFlightDate(taskQueue,info.getEndTime(),true));
						}
					}
					
				}
				if (i == 2) {
					// 舱位信息
					List<CabinInfo> cabinLists=(List<CabinInfo>)obj;
					cabinfos.addAll(cabinLists);
					for(int k=0;k<cabinLists.size();k++){
						ReturnCabinEntity e=new ReturnCabinEntity();
						CabinInfo cabinfo=cabinLists.get(k);
						e.setPrice(cabinfo.getPrice());
						e.setCabinType(cabinTypeLabe);
						e.setProductName(cabinfo.getCabinClass());
						e.setSubCabinName(cabinfo.getRecommendation());
						dpie.getReturnCabins().add(e);
					}
				}
				i++;
			}
		}
		return dpie;
	}
	
	public Date setFlightDate(TaskModel taskQueue,String timeStr,boolean isReturn){
		Date date=null;
		try {
			if (isReturn) {
				date = DateUtil.string2Date(taskQueue.getReturnGrabDate()+" "+timeStr+":00","yyyy-MM-dd HH:mm:ss");
			} else {
				date = DateUtil.string2Date(taskQueue.getFlightDate()+" "+timeStr+":00","yyyy-MM-dd HH:mm:ss");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return date;
	}
	
	// 航班列表页数据解析封装到map中
	private void flightInfoAnalysis (List<Object> outboundsData,List<Object>  inboundsData, Document doc, CabinType cabin) {
		//去程信息
		Elements flightS=doc.select("div#divUpsell_7 table.upsellSMH tr[id^=flight_]");
		Elements featureS=doc.select("div#divUpsell_7 table.upsellSMH tr[id^=features_]");
		Map<String,Element> flightMap=new HashMap<String, Element>();
		Map<String,Element> featureMap=new HashMap<String, Element>();
		Elements outbound =new Elements();
		
		if(flightS.size()>0 && featureS.size()>0){
			for(Element flight:flightS){
				String key=flight.select("tr").first().attr("id").trim().split("_")[1];
				flightMap.put(key, flight);
			}
			
			for(Element feature:featureS){
				String key=feature.select("tr").first().attr("id").trim().split("_")[1];
				featureMap.put(key, feature);
			}
			
			for(Map.Entry<String, Element>flightMaps:flightMap.entrySet()){
				String value=null;
				String key=flightMaps.getKey();
				String value_1=flightMaps.getValue().toString();
				String value_2=featureMap.get(key).toString();
				Elements value_3=doc.select("div#divUpsell_7 table.upsellSMH tr#moreStopovers_"+key);
				if(value_3.size()>0){
					value=value_1.toString()+value_3.toString()+value_2.toString();
				}else{
					value=value_1.toString()+value_2.toString();
				}
				
				if(value !=null && value.length()>0){
					outbound.add(Jsoup.parse("<html><body><table>"+value+"</table></body></html>"));
				}
			}
		}
		
		//回程信息
		Elements BflightS=doc.select("div#divUpsell-back_7 table.upsellSMH tr[id^=flight-back_]");
		Elements BfeatureS=doc.select("div#divUpsell-back_7 table.upsellSMH tr[id^=features-back_]");
		Map<String,Element> BflightMap=new HashMap<String, Element>();
		Map<String,Element> BfeatureMap=new HashMap<String, Element>();
		Elements inbound =new Elements();
		if(BflightS.size()>0 && BfeatureS.size()>0){
			for(Element flight:BflightS){
				String key=flight.select("tr").first().attr("id").trim().split("_")[1];
				BflightMap.put(key, flight);
			}
			
			for(Element feature:BfeatureS){
				String key=feature.select("tr").first().attr("id").trim().split("_")[1];
				BfeatureMap.put(key, feature);
			}
			for(Map.Entry<String, Element>BflightMaps:BflightMap.entrySet()){
				String value=null;
				String key=BflightMaps.getKey();
				String value_1=BflightMaps.getValue().toString();
				String value_2=BfeatureMap.get(key).toString();
				Elements value_3=doc.select("div#divUpsell-back_7 table.upsellSMH tr#moreStopovers-back_"+key);
				if(value_3.size()>0){
					value=value_1.toString()+value_3.toString()+value_2.toString();
				}else{
					value=value_1.toString()+value_2.toString();
				}
				
				if(value !=null && value.length()>0){
					inbound.add(Jsoup.parse("<html><body><table>"+value+"</table></body></html>"));
				}
			}
			
		}
		
		if(outbound.size()>0 && inbound.size()>0){
			for (Element element : outbound) {
				Set<Object> objS=new LinkedHashSet<Object>();
				//舱位价格信息
				Element priceE=element.select("tr[id^=flight_]").first();//舱位信息
				List<CabinInfo>cabinfos=getCabin(priceE,false);
				
				//基础信息
				Element info=element.select("tr[id^=features_]").first();
				Element stopInfo=element.select("tr[id^=moreStopovers]").first();
				List<FlightInfo> baseInfo=getInfo(info,stopInfo);
				
				
				objS.add(baseInfo);//基础信息
				objS.add(cabinfos);//舱位
				if(objS.size()==2){
					outboundsData.add(objS);
				}
			}
			
			logger.debug("======================返程=====================");
			for (Element element : inbound) {
				Set<Object> objS=new LinkedHashSet<Object>();
				//舱位价格信息
				Element priceE=element.select("tr[id^=flight-back_]").first();//舱位信息
				List<CabinInfo>cabinfos=getCabin(priceE,true);
				
				//基础信息
				Element info=element.select("tr[id^=features-back_]").first();
				Element stopInfo=element.select("tr[id^=moreStopovers-back]").first();
				List<FlightInfo> baseInfo=getInfo(info,stopInfo);
				
				objS.add(baseInfo);//基础信息
				objS.add(cabinfos);//舱位信息
				
				if(objS.size()==2){
					inboundsData.add(objS);
				}
			}
		}
		
	}
	
	
	public List<CabinInfo> getCabin(Element cabin,boolean isReturn){
		List<CabinInfo> cabinfo=new ArrayList<CabinInfo>();
		String idkey="";
		Element cabinfos =null; 
		if(isReturn){
			idkey="tr[id^=flight-back_]";
		}else{
			idkey="tr[id^=flight_]";
		}
		cabinfos=cabin.select(idkey).first();
		if(cabinfos !=null){
		Elements cabs=cabinfos.getElementsByClass("cellMiddleSMH");
			for(Element cab:cabs){
				if(cab.text() !="-" && cab.text().contains("CNY")){
					CabinInfo info=new CabinInfo();
					info.setPrice(Double.parseDouble(cab.text().replace("CNY", "").replaceAll(" ", "")));
					String key=cab.select("input[type=radio]").first().attr("onclick").split(";")[0];//displayDetails('1','FFLHAFKLY1','7','0')
					String []cabi=RegHtmlUtil.regStr(key, "displayDetails\\((.*)\\)").split(",");
					info.setRecommendation(cabi[0].replaceAll("'", ""));
					info.setCurrencyCode("CNY");
					info.setCabinClass(cabi[1].replaceAll(" ", "").replaceAll("'", ""));
					cabinfo.add(info);
				}
			}
		}
		return cabinfo;
	}
	
	
	public List<FlightInfo> getInfo(Element infos,Element stopInfo){
		List<FlightInfo> infoLists=new ArrayList<FlightInfo>();
		Elements infoEls=infos.getElementsByClass("grey_details");
		for(int i=0 ;i<infoEls.size();i++){
			Element el=infoEls.get(0);
			FlightInfo info=new FlightInfo();
			Elements tds=el.select("td");
			info.setFlightNo(tds.get(0).select("span").first().text().replaceAll(" ", ""));
			Elements spans_1=tds.get(1).select("span");
			info.setStartTime(spans_1.get(1).text());
			info.setFromAirportName(spans_1.get(2).text());
			info.setEndTime(spans_1.get(4).text());
			info.setToAirportName(spans_1.get(5).text());
			info.setFlightDuration((spans_1.get(6).text() !=null&& !spans_1.get(6).text().equals(""))?setFlightTime(RegHtmlUtil.regStr(spans_1.get(6).text(),"(\\d{1,2}h\\d{1,2})")):0l);
			
			info.setAgentName(tds.get(2).select("span").first().text().split("\\ ")[1]);
			Elements span_2=tds.get(3).select("span");
			info.setFlightType(span_2.first().text().split(":")[1].replaceAll(" ", ""));
			info.setCabinName(span_2.get(1).text().split(":")[1].replaceAll(" ", ""));
			if(i==0 && stopInfo !=null && stopInfo.getElementsByClass("message")!=null){
				List<String> timeLists=getPatternList(stopInfo.select("td").text(),"(\\d{1,2}h\\d{1,2})"," ","");
				info.setFlightDuration(setFlightTime(timeLists.get(0)));//飞行总时间
				info.setStopTime(setFlightTime(timeLists.get(1)));//停留时间
				
			}
			infoLists.add(info);
		}
		
		return infoLists;
	}
	
	private List<String> getPatternList(String content, String regEx, String replace, String replacement){
		Pattern p=Pattern.compile(regEx, Pattern.DOTALL|Pattern.MULTILINE);
		Matcher m=p.matcher(content);
		List<String> strList = new ArrayList<String>();
		while(m.find()){
			strList.add(m.group(1).trim().replaceAll(replace, replacement));
		}
		return strList;
	}
	
	public Long setFlightTime(String timeStr){
		long l=0l;
		String []time=timeStr.split("h");
		l+=Long.parseLong(time[0])*60;
		String m=time[1].substring(0,time[1].length()-1);
		l+=Long.parseLong(m);
		return l*1000*60;
	}

	
	
	/**
	 * 获取详细页面
	 * 
	 * @param form
	 * @param outbound
	 * @param inbound
	 */
	private void analyzeCabinRelation(Document detailDoc, DoublePlaneInfoEntity dpie, Set<CabinEntity> cabins, Set<ReturnCabinEntity> returnCabins) {
		String taxation = null;
		String bookTicketsPrice = null;
		String nakedPrce = null;
		String totalPrice =  null;
		
		// 如果抓取税费
		if (isFetchTaxation) {
			nakedPrce = detailDoc.select("#horsTaxe0").text();
			taxation = detailDoc.select("#taxe0").text();
			bookTicketsPrice = detailDoc.select("#fees0").text();
			totalPrice =  detailDoc.select("#total0").text();
			nakedPrce = StringUtils.isBlank(nakedPrce) ? "0" : nakedPrce.replaceAll("CNY|\\s| *", "");
			taxation = StringUtils.isBlank(taxation) ? "0" : taxation.replaceAll("\\+|CNY|\\s| *", "");
			bookTicketsPrice = StringUtils.isBlank(bookTicketsPrice) ? "0" : bookTicketsPrice.replaceAll("\\+|CNY|\\s| *", "");
			totalPrice = StringUtils.isBlank(totalPrice) ? "0" : totalPrice.replaceAll("=|CNY|\\s| *", "");
		}
		
		// 设置仓位对应关系
		for (CabinEntity cabin : cabins) {
			for (ReturnCabinEntity rcabin : returnCabins) {
				CabinRelationEntity cre = new CabinRelationEntity();
				cre.setCabinId(cabin.getId());
				cre.setReturnCabinId(rcabin.getId());
				cre.setFullPrice(isFetchTaxation ? Double.parseDouble(nakedPrce) : (cabin.getPrice() + rcabin.getPrice()) );
				cre.setTaxesPrice(isFetchTaxation ? Double.parseDouble(taxation) : 0);
				cre.setTotalFullPrice(isFetchTaxation ? Double.parseDouble(totalPrice) : (cre.getFullPrice() + cre.getTaxesPrice()));
				dpie.getCabinRelations().add(cre);
			}
		}
	}
	
	private String errorRepeatExecute(String parmsUrl) {
		String content = null;
		int timeError = 0;
		boolean error = false;

		do {
			try {
				htmlPage = webClient.getPage(parmsUrl);
				//阻塞线程js执行完毕或者达到指定时间
				webClient.waitForBackgroundJavaScriptStartingBefore(PAGE_MAX_WAIT);
				content = htmlPage.asXml();
			} catch (Exception e) {
				error = true;
				timeError++;
				logger.error("获取法国航空信息第{}次出错:{}", timeError, e.getMessage());
				if (timeError >= REPEATE_TIME) {
					logger.error("深度获取法国航空信息异常，中止尝试", e);
				} else {
					adapter.switchProxyipByWebClient();
				}
			}
		} while (error || StringUtils.isBlank(content));

		return content;
	}

	private void hasWebClientRedirectEnabled(){
		webClient.getOptions().setRedirectEnabled(true);
		webClient.getOptions().setJavaScriptEnabled(true);
		webClient.getOptions().setActiveXNative(false);
		webClient.getOptions().setCssEnabled(false);
		webClient.getOptions().setThrowExceptionOnScriptError(false);
		webClient.setAjaxController(new NicelyResynchronizingAjaxController());
	}
	
	
	// 第二页面，日历选择页面
	private boolean standardCalendarPageVerify(String page) {
		boolean result  = false;
		Document doc = null;
		
		if (StringUtils.isNotBlank(page)) {
			doc = Jsoup.parse(page);
			Elements form  = doc.select("div.blocMain > form[name=standardCalendarForm]");
			result = form.isEmpty() ? result : true;
		}
		
		return result;
	}
	
	// 航班列表页面验证
	private boolean flightListPageVerify(String flightPage) {
		boolean result  = false;
		Document doc = null;
		
		if (StringUtils.isNotBlank(flightPage)) {
			 doc = Jsoup.parse(flightPage);
			Elements select  = doc.select("select[id^=idSortTypeSelect]");
			result = select.isEmpty() ? result : true;
		}
		
		return result;
	}

	private String getEnterParamsUrl(String cablin) {
		StringBuilder url = new StringBuilder(enterUrl);
		String flightDate = null;
		String returnGrabDate = null;
		
		try {
			flightDate = DateUtil.String2String(taskQueue.getFlightDate(), "yyyy-MM-dd", "yyyyMM");
			returnGrabDate = DateUtil.String2String(taskQueue.getReturnGrabDate(), "yyyy-MM-dd", "yyyyMM");
		} catch (ParseException e) {
			AirfranceAdapter.logger.error("参数时间格式化处理出错 : ", e);
		} 
				
		url.append("?")
		.append("arrival=").append(taskQueue.getToCity())
		.append("&arrival=").append(taskQueue.getFromCity())
		.append("&cabin=").append(cablin.split("_")[0])
		.append("&dayDate=").append(taskQueue.getFlightDate().substring(taskQueue.getFlightDate().lastIndexOf("-") + 1))
		.append("&dayDate=").append(taskQueue.getReturnGrabDate().substring(taskQueue.getReturnGrabDate().lastIndexOf("-") + 1))
		.append("&departure=").append(taskQueue.getFromCity())
		.append("&departure=").append(taskQueue.getToCity())
		.append("&familyTrip=").append("NON")
		.append("&haul=").append("LH")
		.append("&idArrivalTrip1Lib=").append(taskQueue.getToCity() + " (" + taskQueue.getToCity() + ")")
		.append("&idDepartureTrip1Lib=").append(taskQueue.getFromCity() +  " (" + taskQueue.getFromCity() + ")")
		.append("&isUM=").append("")
		.append("&jourAllerFin=").append("06")
		.append("&jourAllerOrigine=").append("11")
		.append("&moisAllerFin=").append("201509")
		.append("&moisAllerOrigine=").append("201409")
		.append("&nbEnfants=").append("")
		.append("&nbPassenger=").append("1")
		.append("&paxTypoList=").append("ADT")
		.append("&paxTypoList=").append("ADT")
		.append("&paxTypoList=").append("ADT")
		.append("&paxTypoList=").append("ADT")
		.append("&plusOptions=").append("")
		.append("&selectCabin=").append("Y_MCHER")
		.append("&selectCabin=").append("Y_MCHER")
		.append("&selectCabin=").append(cablin)
		.append("&selectCabin=").append("Y_MCHER")
		.append("&selectPreviousSearch=").append(taskQueue.getFromCity() + "-" + taskQueue.getToCity() + "_2014811")
		.append("&subCabin=").append(cablin.split("_")[1])
		.append("&typeTrip=").append("2")
		.append("&yearMonthDate=").append(flightDate)
		.append("&yearMonthDate=").append(returnGrabDate);
		
		return url.toString();
	}
	
	
	private String getPriceParams(CabinInfo out,CabinInfo in,List<FlightInfo>outList,List<FlightInfo>inList) throws Exception{
		StringBuffer url=new StringBuffer("http://www.airfrance.com.cn/cgi-bin/AF/CN/zh/local/process/standardbooking/DisplayFlightPageAction.do?");
		url.append("method=getInboundUpsellAction");
		url.append("&filterDirect=0");
		url.append("&filterValDate=0");
		
		url.append("&inFilters%5B%5D=9");
		url.append("&inFilters%5B%5D=15");
		url.append("&inFilters%5B%5D=21");
		url.append("&inFilters%5B%5D=0");
		for(FlightInfo o:outList){
			url.append("&flightNumbers%5B%5D="+o.getFlightNo().replaceAll("\\ ", "%26nbsp%3B"));
		}
		for(FlightInfo i:inList){
			url.append("&flightInNumbers%5B%5D="+i.getFlightNo().replaceAll("\\ ", "%26nbsp%3B"));
		}
		url.append("&outFilters%5B%5D=9");
		url.append("&outFilters%5B%5D=0");		
		
		url.append("&dateDeparture="+DateUtil.dateAddHour(DateUtil.string2Date(taskQueue.getFlightDate(),"yyyy-MM-dd"),8).getTime());
		url.append("&dateDepartureBack="+DateUtil.dateAddHour(DateUtil.string2Date(taskQueue.getReturnGrabDate(), "yyyy-MM-dd"),8).getTime());
		url.append("&idFareFamily="+out.getCabinClass());
		url.append("&idInFareFamily="+in.getCabinClass());
		url.append("&idInRecommendation="+in.getRecommendation());
		url.append("&idRecommendation="+out.getRecommendation());
		
		return url.toString();
	}
	
	
	private String getFetchTaxationParams(HtmlForm form, String outbound, String inbound){
		StringBuilder url = new StringBuilder("http://www.airfrance.com.cn/cgi-bin/AF/CN/zh/local/process/standardbooking/FareAction.do?");
		String indexItinerary = form.getInputByName("indexItinerary").getValueAttribute();
		url.append("&indexItinerary=").append(indexItinerary);
		List<HtmlInput>  prices = form.getInputsByName("price");
		List<HtmlInput>  priceMultiPaxs = form.getInputsByName("priceMultiPax");
		List<HtmlInput>  selectedFFs = form.getInputsByName("selectedFF");
		List<HtmlInput>  recommendations = form.getInputsByName("recommendation");
		
		for (HtmlInput price : prices) {
			url.append("&price=").append(price.getValueAttribute());
		}
		
		for (HtmlInput priceMultiPax : priceMultiPaxs) {
			url.append("&priceMultiPax=").append(priceMultiPax.getValueAttribute());
		}
		
		for (HtmlInput selectedFF : selectedFFs) {
			url.append("&selectedFF=").append(selectedFF.getValueAttribute());
		}
		
		url.append("&radioIti0=").append(outbound.trim())
		   .append("&radioIti1=").append(inbound.trim());
		
		for (HtmlInput recommendation : recommendations) {
			url.append("&recommendation=").append(recommendation.getValueAttribute());
		}
		   // 排序类型写死
		url.append("&sortType=DEPARTURE")
		   .append("&sortType=DEPARTURE")
		   .append("&sortType0=DEPARTURE")
		   .append("&sortType1=DEPARTURE");
		
		return url.toString();
	}
	
	/**
	 * 记录活动日志，主要是记录到task中
	 * 
	 * @param info
	 */
	private void logActionInfo(String info) {
		logger.info(info);
		//adapter.logInfo(info);
	}

	

	//航班基础信息
	private class FlightInfo{
		private String TstartTime;//出发时间
		private String TendTime;//到达时间
		private String flightNo;//航班号
		private String startTime;//起飞时间
		private String endTime;//结束时间
		private String fromAirport;//起飞城市机场
		private String toAirport;//到达城市机场
		private String fromAirportName; 
		private String toAirportName;
		private String flightType;//飞机类型
		private Long stopTime;//停留时间
		private Long flightDuration;//飞行总时间
		private String agentName;//代理商名称
		private String cabinName;//大舱位   如：经济客舱
		public String getFlightNo() {
			return flightNo;
		}
		public void setFlightNo(String flightNo) {
			this.flightNo = flightNo;
		}
		public String getTstartTime() {
			return TstartTime;
		}
		public void setTstartTime(String tstartTime) {
			TstartTime = tstartTime;
		}
		public String getTendTime() {
			return TendTime;
		}
		public void setTendTime(String tendTime) {
			TendTime = tendTime;
		}
		public String getStartTime() {
			return startTime;
		}
		public void setStartTime(String startTime) {
			this.startTime = startTime;
		}
		public String getEndTime() {
			return endTime;
		}
		public void setEndTime(String endTime) {
			this.endTime = endTime;
		}
		public String getFromAirport() {
			return fromAirport;
		}
		public void setFromAirport(String fromAirport) {
			this.fromAirport = fromAirport;
		}
		public String getToAirport() {
			return toAirport;
		}
		public void setToAirport(String toAirport) {
			this.toAirport = toAirport;
		}
		
		public String getFromAirportName() {
			return fromAirportName;
		}
		public void setFromAirportName(String fromAirportName) {
			this.fromAirportName = fromAirportName;
		}
		public String getToAirportName() {
			return toAirportName;
		}
		public void setToAirportName(String toAirportName) {
			this.toAirportName = toAirportName;
		}
		public String getFlightType() {
			return flightType;
		}
		public void setFlightType(String flightType) {
			this.flightType = flightType;
		}
		public Long getStopTime() {
			return stopTime;
		}
		public void setStopTime(Long stopTime) {
			this.stopTime = stopTime;
		}
		public Long getFlightDuration() {
			return flightDuration;
		}
		public void setFlightDuration(Long flightDuration) {
			this.flightDuration = flightDuration;
		}
		public String getAgentName() {
			return agentName;
		}
		public void setAgentName(String agentName) {
			this.agentName = agentName;
		}
		public String getCabinName() {
			return cabinName;
		}
		public void setCabinName(String cabinName) {
			this.cabinName = cabinName;
		}
	}
		
	//价格信息
	private class CabinInfo{
		private String cabinClass;
		private String Recommendation;
		private Double price;//价格
		private String currencyCode;//货币单位
		public String getCabinClass() {
			return cabinClass;
		}
		public void setCabinClass(String cabinClass) {
			this.cabinClass = cabinClass;
		}
		public String getCurrencyCode() {
			return currencyCode;
		}
		public void setCurrencyCode(String currencyCode) {
			this.currencyCode = currencyCode;
		}
		public String getRecommendation() {
			return Recommendation;
		}
		public void setRecommendation(String recommendation) {
			Recommendation = recommendation;
		}
		public Double getPrice() {
			return price;
		}
		public void setPrice(Double price) {
			this.price = price;
		}
		
	}
	
}
